package org.gaaidou.ptarmigan.springboot.functional.util;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.util.JsonExpectationsHelper;

@Slf4j
public class RestfulSender {

    private final TestRestTemplate restTemplate;

    private final int port;

    private String uri;
    private HttpHeaders reqHeader;
    private String reqJson;

    private HttpMethod httpMethod;

    private ResponseEntity<String> resp;

    private final JsonExpectationsHelper jsonHelper = new JsonExpectationsHelper();

    private RestfulSender(TestRestTemplate restTemplate, int port) {
        this.restTemplate = restTemplate;
        this.port = port;
    }

    public static RestfulSender start(TestRestTemplate restTemplate, int port) {
        return new RestfulSender(restTemplate, port);
    }

    public RestfulSender uri(String uri) {
        this.uri = uri;
        return this;
    }

    public RestfulSender header(HttpHeaders reqHeader) {
        this.reqHeader = reqHeader;
        return this;
    }

    public RestfulSender body(String reqJson) {
        this.reqJson = reqJson;
        return this;
    }

    public RestfulSender method(HttpMethod httpMethod) {
        this.httpMethod = httpMethod;
        return this;
    }

    public RestfulSender send() {
        this.resp = restTemplate.exchange("http://localhost:" + port + uri, httpMethod, new HttpEntity<>(reqJson, reqHeader), String.class);
        return this;
    }

    @SneakyThrows
    public RestfulSender expectStatus(HttpStatus httpStatus) {
        Assertions.assertEquals(httpStatus.value(), resp.getStatusCode().value());
        return this;
    }

    @SneakyThrows
    public RestfulSender expectBody(String expectJson) {
        String body = resp.getBody();
        log.info("actual response body: {}", body);
        jsonHelper.assertJsonEqual(expectJson, body);
        return this;
    }

    public RestfulSender expectHeader(String key, String value) {
        Assertions.assertTrue(resp.getHeaders().containsKey(key));
        Assertions.assertTrue(resp.getHeaders().get(key).contains(value));
        return this;
    }
}
